package org.anderground.modules.editor.tools.geocoding;

import geo.google.GeoAddressStandardizer;
import geo.google.GeoException;
import geo.google.datamodel.GeoAddress;
import geo.google.datamodel.GeoCoordinate;
import geo.google.datamodel.GeoStatusCode;

import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.List;

import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;

import org.anderground.core.Logger;
import org.anderground.core.model.Editor;
import org.anderground.core.model.ModelData;
import org.anderground.core.model.Station;
import org.anderground.core.util.Coord;

/**
 * @author Ilya Shurigyn
 */
@SuppressWarnings("serial")
public class Geowindow extends JDialog {

	private JProgressBar progressBar;
	private StatPanel statPanel;
	private Thread coordsLoading;
	private Details details;
	ModelData data;

	public Geowindow(final ModelData data) {
		this(data, null);
	}

	public Geowindow(final ModelData data, Frame parent) {
		super(parent, true);
		this.data = data;
		this.progressBar = new JProgressBar(0, data.getStations().size());
		this.getContentPane().setLayout(
				new BoxLayout(this.getContentPane(), BoxLayout.Y_AXIS));
		this.getContentPane().add(progressBar);
		statPanel = new StatPanel();
		details = new Details(data, this);
		this.getContentPane().add(statPanel);
		this.getContentPane().add(details);
		JPanel buttonPanel = new JPanel();
		buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
		JButton ok = new JButton("OK");
		JButton cancel = new JButton("Cancel");
		buttonPanel.add(ok);
		buttonPanel.add(cancel);
		add(buttonPanel);
		ok.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent arg0) {
				onOk();
			}

		});
		cancel.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent arg0) {
				onCancel();
			}

		});
		addWindowListener(new WindowAdapter() {

			@Override
			public void windowClosing(WindowEvent arg0) {
				stop();

			}

		});

		coordsLoading = new Thread(new Runnable() {

			@Override
			public void run() {

				GeoAddressStandardizer standardizer = new GeoAddressStandardizer(
						GoogleAPIDeveloperData.API_KEY, 1000);
				String request;

				try {
					for (Station station : data.getStations()) {
						Logger.d("fetching " + station);
						request = getRequestForStation(data, station);
						List<GeoAddress> geoAddresses = null;
						try {
							geoAddresses = standardizer
									.standardizeToGeoAddresses(request);

							if (geoAddresses.size() > 1) {
								statPanel.incSkipped();
							} else if (geoAddresses.size() == 1) {
								statPanel.incSuccessfull();
							}
							for (GeoAddress geoAddress : geoAddresses) {
								GeoCoordinate geoCoordinate = geoAddress
										.getCoordinate();
								Logger.d("lat: " + geoCoordinate.getLatitude()
										+ "; lon: "
										+ geoCoordinate.getLongitude());
							}
						} catch (geo.google.GeoException e) {
							if (e.getStatus() == GeoStatusCode.G_GEO_UNKNOWN_ADDRESS) {
								Logger.w("cannot find address:" + request);
								statPanel.incFailed();
							} else
								throw e;
						} finally {
							progressBar.setValue(progressBar.getValue() + 1);
							details.log(station, (geoAddresses == null) ? null
									: geoAddresses.toArray(new GeoAddress[1]));
							// pack();
						}
					}

				} catch (GeoException e) {
					// GeoStatusCode.G_GEO_UNKOWN_STATUS - sleep interupted(on
					// window cancel)
					if (e.getStatus() != GeoStatusCode.G_GEO_UNKOWN_STATUS) {
						e.printStackTrace();
					}
				}
			}

		});
		coordsLoading.start();
		this.pack();
	}

	private void onCancel() {
		stop();
		this.setVisible(false);

	}

	protected void onOk() {
		stop();
		for (Details.Entry entry : details.getEntries()) {
			new Editor() {
				public void setCoord(Station station, GeoAddress address) {
					if (address != null) {
						getEditor(station)
								.setLocation(
										new Coord(
												(int) (address.getCoordinate()
														.getLatitude() * 1e6),
												(int) (address.getCoordinate()
														.getLongitude() * 1e6)));
					}
				}
			}.setCoord(entry.getStation(), entry.getAddress());

		}
		this.setVisible(false);
	}

	public static String getRequestForStation(ModelData data, Station station) {
		return data.getCity().getName() + ", subway " + station.getName();
	}

	StatPanel getStatPanel() {
		return statPanel;
	}

	private void stop() {
		try {
			coordsLoading.interrupt();
		} catch (Exception e) {
		}
	}
}

@/**
 * @author Ilya Shurigyn
 */
SuppressWarnings("serial")
class StatPanel extends JPanel {
	private int failedVal;
	private int successfullVal;
	private int skippedVal;
	private JLabel successfull = new JLabel();
	private JLabel skipped = new JLabel();
	private JLabel failed = new JLabel();

	public StatPanel() {
		super();
		failedVal = 0;
		successfullVal = 0;
		skippedVal = 0;
		this.setLayout(new GridLayout(0, 3));
		this.add(successfull);
		this.add(skipped);
		this.add(failed);
		update();
	}

	public void incFailed() {
		this.failedVal++;
		update();
	}

	public void incSkipped() {
		this.skippedVal++;
		update();
	}

	public void incSuccessfull() {
		this.successfullVal++;
		update();
	}

	public void decFailed() {
		this.failedVal--;
		update();
	}

	public void decSkipped() {
		this.skippedVal--;
		update();
	}

	public void decSuccessfull() {
		this.successfullVal--;
		update();
	}

	private void update() {
		successfull.setText("<html><font color=#0000aa>" + successfullVal
				+ " Successful</font></html>");
		skipped.setText("<html><font color=#bb7700>" + skippedVal
				+ " Multichoice </font></html>");
		failed.setText("<html><font color=#aa0000>" + failedVal
				+ " Failed</font></html>");
	}

}
